#include <Precomp.h>
                                                        
#include <AVUIFrameworkElement.h>
#include <AVUIListView.h>
#include "defs.h"
#include "Application.h"                                
#include "ServerConnection.h"
#include "ClientListener.h"
#include "BaseGameState.h"
#include "GameStateGetServerName.h"
#include "UIManager.h"
#include "GameWorld.h"
#include "AVUIButton.h"
#include "AVUITextBox.h"
#include "AVUIDispatcher.h"
#include "AVUIInputManager.h"
#include "AVUIDispatcherTimer.h"
#include "AVUINavigationWindow.h"
#include "AVUIItemCollection.h"
#include "AVUITransitioningPage.h"

using namespace AVUI;

const char* CGameStateGetServerName::cs_szMetaserver = "metaserver.us.netrek.org";

struct ServerEntry
{
    ServerEntry(const char* szName, int portNumber, const char* szStatus, const char* szGameType, const char* szAge)
    {
        strcpy_s(m_szName, sizeof(m_szName), szName);
        m_portNumber = portNumber;
        strcpy_s(m_szStatus, sizeof(m_szStatus), szStatus);
        strcpy_s(m_szGameType, sizeof(m_szGameType), szGameType);
        strcpy_s(m_szAge, sizeof(m_szAge), szAge);
    }

    const char* get_Name() { return m_szName; }
    int get_PortNumber() { return m_portNumber; }
    const char* get_Status() { return m_szStatus; }
    const char* get_GameType() { return m_szGameType; }
    const char* get_Age() { return m_szAge; }

    bool operator==(const ServerEntry& rhs) const 
    { 
        if(strcmp(m_szName, rhs.m_szName))
        {
            return false;
        }

        if(strcmp(m_szGameType, rhs.m_szGameType))
        {
            return false;
        }

        if(strcmp(m_szAge, rhs.m_szAge))
        {
            return false;
        }

        if(strcmp(m_szStatus, rhs.m_szStatus))
        {
            return false;
        }

        if(m_portNumber != rhs.m_portNumber)
        {
            return false;
        }

        return true; 
    }

    DECLARE_VALUE_ELEMENT(ServerEntry);
    IMPLEMENT_READONLY_VALUE_PROPERTY(Name, const char*, false);
    IMPLEMENT_READONLY_VALUE_PROPERTY(PortNumber, int, false);
    IMPLEMENT_READONLY_VALUE_PROPERTY(Status, const char*, false);
    IMPLEMENT_READONLY_VALUE_PROPERTY(GameType, const char*, false);
    IMPLEMENT_READONLY_VALUE_PROPERTY(Age, const char*, false);

    char m_szName[80];
    int m_portNumber;
    char m_szStatus[80];
    char m_szGameType[80];
    char m_szAge[80];
};

REGISTER_VALUE_TYPE_BEGIN(ServerEntry)
    REGISTER_PROPERTY(Name);
    REGISTER_PROPERTY(PortNumber);
    REGISTER_PROPERTY(Status);
    REGISTER_PROPERTY(GameType);
    REGISTER_PROPERTY(Age);
REGISTER_VALUE_TYPE_END()



void CGameStateGetServerName::Initialize(CNetrekClientListener* pListener)
{
    CBaseGameState::Initialize(pListener);

    m_pBaseConnection = new CBaseConnection();

    m_pListener->GetGameWorld()->Reset();

    m_pBaseConnection->Connect(cs_szMetaserver, cs_wMetaserverPort);

    FrameworkElement* pFE = CUIManager::LoadXamlScene(L"Media\\Xaml\\GetServerName.xaml");
    m_pRoot = pFE;

    ((NavigationWindow*)Application::get_Current()->get_MainWindow())->Navigate(m_pRoot);

    if(m_pRoot != NULL)
    {
        RoutedEventArgs eventArgs(TransitioningPage::get_TransitionInEvent());
        m_pRoot->RaiseEvent(&eventArgs);
    }


    pFE->Release();
    pFE = NULL;

    Button* pButton = object_cast<Button>(m_pRoot->FindName(object_allocate<String>(L"ButtonConnect")));
    pButton->add_Click(RoutedEventHandler::Create(this, &CGameStateGetServerName::ConnectButtonClicked));

    m_pList = object_cast<ListView>(m_pRoot->FindName(object_allocate<String>(L"ServerList")));
    m_pList->add_MouseDown(MouseButtonEventHandler::Create(this, &CGameStateGetServerName::ListClicked));
    m_pList->add_SelectionChanged(SelectionChangedEventHandler::Create(this, &CGameStateGetServerName::ListSelectionChanged));
}

const char* GameTypeToText(char chGameType)
{
    if(chGameType == 'B')
        return "BRONCO";

    if(chGameType == 'H')
        return "HOCKEY";

    return "UNKNOWN";
}


void TruncateAtFirstDoubleSpace(char* szBuf, int cchBuf)
{
    for(int i = 0; i < cchBuf - 1; i++)
    {
        if(szBuf[i] == ' ' && szBuf[i + 1] == ' ')
        {
            szBuf[i] = '\0';
            break;
        }
    }
}



void CGameStateGetServerName::ProcessMetaserverData(const char* pbData, int cbData)
{
    if(cbData < 2)
    {
        return;
    }

    char chGameType = pbData[cbData - 1];
    if(chGameType == 'P')
    {
        return;
    }

    char szServerName[81];
    char szPortNumber[33];  
    char szAge[33];

    if(sscanf_s(pbData, "-h %80s -p %32s %32s", szServerName, 81, szPortNumber, 33, szAge, 33) != 3)
    {
        return;
    }
    char szStatusBuf[20];

    strncpy_s(szStatusBuf, 20, pbData + 54, sizeof(szStatusBuf) - 1);
    szStatusBuf[sizeof(szStatusBuf) - 1] = '\0';

    TruncateAtFirstDoubleSpace(szStatusBuf, sizeof(szStatusBuf));

    m_pList->get_Items()->Add(BoxValue(ServerEntry(szServerName, atoi(szPortNumber), szStatusBuf, GameTypeToText(chGameType), szAge)));
}

void CGameStateGetServerName::FrameStart()
{
    m_pBaseConnection->Update();


    bool fProcessed = true;
    while(fProcessed)
    {
        fProcessed = false;

        int cbBuffered = m_pBaseConnection->GetCBBufferedRead();
        BYTE* pbReadBuffer = m_pBaseConnection->GetReadBufferHead();

        for(int i = 0; i < cbBuffered; i++)
        {
            if(pbReadBuffer[i] == '\n')
            {
                pbReadBuffer[i] = '\0';

                ProcessMetaserverData((const char*)pbReadBuffer, i);
                m_pBaseConnection->ConsumeReadBuffer(i + 1);
                fProcessed = true;
                break;
            }       
        }
    }
}

void CGameStateGetServerName::Cleanup()
{
    Application::get_Current()->get_MainWindow()->set_Content(NULL);
}

void CGameStateGetServerName::ConnectButtonClicked(Object* pSender, RoutedEventArgs* pArgs)
{
    char szServerName[80] = { 0 };

    TextBox* pTextBoxServerName = (TextBox*) m_pList->FindName(object_allocate<String>(L"ServerName"));
    TextBox* pTextBoxPort = (TextBox*) m_pList->FindName(object_allocate<String>(L"ServerPort"));

    if(String::IsNullOrEmpty(pTextBoxServerName->get_Text()))
    {
        m_pListener->GetUIManager()->ShowOKDialog(L"Please specify a server name.", DialogResultCallback(&CGameStateGetServerName::ErrorDialogOK, this));
        return;
    }

    if(String::IsNullOrEmpty(pTextBoxPort->get_Text()))
    {
        m_pListener->GetUIManager()->ShowOKDialog(L"Please specify a port.", DialogResultCallback(&CGameStateGetServerName::ErrorDialogOK, this));
        return;
    }

    pTextBoxServerName->get_Text()->ConvertToAnsi(szServerName, sizeof(szServerName));

    WORD wPort = (WORD) _wtoi(pTextBoxPort->get_Text()->get_Ptr());

    if(m_pListener->GetServerConnection()->Connect(szServerName, wPort))
    {
        m_pListener->GetServerConnection()->SendPickSocket();

        TransitionMoveToNewState(m_pRoot, eNetrekClientState_Login);
    }
    else
    {
        m_pListener->GetUIManager()->ShowOKDialog(L"Could not connect to server.", DialogResultCallback(&CGameStateGetServerName::ErrorDialogOK, this));
    }
}

void CGameStateGetServerName::ListSelectionChanged(Object* pSender, SelectionChangedEventArgs* pArgs)
{
    if(m_pList->get_SelectedItem() == NULL)
    {
        return;
    }

    ServerEntry selectedItem = UnboxValue<ServerEntry>(m_pList->get_SelectedItem());


    TextBox* pTextBoxServerName = (TextBox*) m_pList->FindName(object_allocate<String>(L"ServerName"));
    pTextBoxServerName->set_Text(object_allocate<String>(selectedItem.get_Name()));


    WCHAR wzText[20];

    _itow_s(selectedItem.get_PortNumber(), wzText, sizeof(wzText) / sizeof(wzText[0]), 10);

    TextBox* pTextBoxPort = (TextBox*) m_pList->FindName(object_allocate<String>(L"ServerPort"));
    pTextBoxPort->set_Text(object_allocate<String>(wzText));

}

void CGameStateGetServerName::ListClicked(AVUI::Object* pSender, AVUI::MouseButtonEventArgs* pEventArgs)
{
    /*
    if(pEventArgs->get_ClickCount() == 2)
    {
        ConnectButtonClicked(pSender, NULL);
    }
    */
}
                  

void CBaseGameState::TransitionMoveToNewState(AVUI::FrameworkElement* pRoot, ENetrekClientState eNewState)
{
    m_eNewStatePostTransition = eNewState;

    Dispatcher::get_CurrentDispatcher()->get_InputManager()->LockInputs();

    if(pRoot != NULL)
    {
        RoutedEventArgs eventArgs(TransitioningPage::get_TransitionOutEvent());
        pRoot->RaiseEvent(&eventArgs);
    }

    TRefCountedPtr<DispatcherTimer> pTimer = object_allocate<DispatcherTimer>(TimeSpan::FromMilliseconds(500), EventHandler::Create(this, &CBaseGameState::MoveToNewStatePostTransition));


    pTimer->Start();
}


void CBaseGameState::MoveToNewStatePostTransition(AVUI::Object* pSender, AVUI::EventArgs* pEventArgs)
{
    ((DispatcherTimer*)pSender)->Stop();

    Dispatcher::get_CurrentDispatcher()->get_InputManager()->UnlockInputs();

    m_pListener->MoveToNewState(m_eNewStatePostTransition);
}

                                  
